#include "types.h"
#include "task.h"
#include "lib.h"
#include "hwirq.h"
#include "riscv_asm.h"

#define STACK_SIZE	1024u
#define MAX_TASKS	10u

/* defined in context.S */
extern void switch_to(struct context_t *next_task);

/* global var */
struct context_t ctx_tasks[MAX_TASKS];

uint8_t __attribute__((aligned(16))) task_stack[MAX_TASKS][STACK_SIZE];

static uint32_t _top = 0;  //  mark the max available position of ctx_tasks
static int32_t _current = -1;  // point to the context of current task


static void mscratch_init(uint64_t x)
{
	asm volatile("csrw mscratch, %0"
								:
								: "r" (x));
}

void task_delay(volatile uint32_t count)
{
	count *= 50000;
	while (count--);
}


/*
 * implment a simple cycle FIFO schedular
 */
void schedule()
{
	if ( _top <= 0) {
		panic("Num of task should be greater than zero!");
		return;
	}

	_current = (_current + 1) % _top;
	struct context_t *next = &ctx_tasks[_current];
	switch_to(next);
}

void sched_init()
{
	mscratch_init(0);  // the first time, mscratch is init as zero
}

void task_yield()
{
	// uint64_t hart = csr_read(mhartid);
	// *(uint32_t *)CLINT_MSIP(hart) = 1;
	/*
	 * Task 0: Created!
	 * Task 0: Running...
	 * Sync exceptions! Code = 2
	 * panic: OOPS!
	 *-----------------------------
	 * in task, “exception code 2” occurs when calling task_yield with access to mhartid.
	 * why?
	 */
	*(uint32_t *)CLINT_MSIP_H0 =1;
}

/*
 * DESCRIPTION
 * Create a task.
 * - task_entry: task routine entry
 * RETURN VALUE
 * 0: success
 * -1: failed
 */
int32_t task_create(void (*task_entry)(void))
{

	if (_top >= MAX_TASKS)
		return -1;

	if (_top < MAX_TASKS && _top >= 0) {
		ctx_tasks[_top].sp = (uint64_t)&task_stack[_top][STACK_SIZE];
		ctx_tasks[_top].epc = (uint64_t)task_entry;
		_top++;
	}

	return 0;
}
